package cn.patient.pp.module.report.service;

import cn.patient.pp.framework.common.pojo.CommonResult;
import cn.patient.pp.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.patient.pp.framework.security.core.LoginUser;
import cn.patient.pp.module.patients.controller.admin.vo.PatientsDOSaveReqVO;
import cn.patient.pp.module.patients.dal.dataobject.patients.PatientsDODO;
import cn.patient.pp.module.patients.framework.web.config.Config;
import cn.patient.pp.module.patients.framework.web.config.LogRecordConstants;
import cn.patient.pp.module.patients.service.BigScreenService;
import cn.patient.pp.module.patients.service.PatientsDOService;
import cn.patient.pp.module.report.ReportConstant;
import cn.patient.pp.module.report.controller.admin.vo.PatientInfoPageReqVO;
import cn.patient.pp.module.report.controller.admin.vo.PatientInfoSaveReqVO;
import cn.patient.pp.module.report.dal.dataobject.report.PatientInfoDO;
import cn.patient.pp.module.report.dal.mysql.report.ReportMapper;
import cn.patient.pp.module.system.dal.dataobject.dept.DeptDO;
import cn.patient.pp.module.system.dal.dataobject.social.SocialClientDO;
import cn.patient.pp.module.system.dal.dataobject.user.AdminUserDO;
import cn.patient.pp.module.system.service.dept.DeptService;
import cn.patient.pp.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.starter.annotation.LogRecord;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import cn.patient.pp.framework.common.pojo.PageResult;
import cn.patient.pp.framework.common.util.object.BeanUtils;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static cn.patient.pp.framework.common.exception.enums.GlobalErrorCodeConstants.SUCCESS;
import static cn.patient.pp.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.patient.pp.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.patient.pp.framework.common.pojo.CommonResult.error;
import static cn.patient.pp.framework.common.pojo.CommonResult.success;
import static cn.patient.pp.module.infra.enums.ErrorCodeConstants.PATIENT_INFO_NOT_EXISTS;
import static cn.patient.pp.module.system.dal.redis.RedisKeyConstants.PATIENTS_PAGE;

/**
 * 上报精神病患者信息 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
public class PatientInfoServiceImpl implements PatientInfoService {

    @Resource
    private ReportMapper patientInfoMapper;
    @Resource
    private DeptService deptService;
    @Resource
    private AdminUserService userService;
    @Resource
    private PatientsDOService patientsDOService;

    @Resource
    private AdminUserService adminUserService;
    @Resource
    private BigScreenService bigScreenService;



        CommonResult<Long> createPatient (PatientInfoSaveReqVO createReqVO, LoginUser loginUser){
        PatientInfoDO patientInfo = BeanUtils.toBean(createReqVO, PatientInfoDO.class);
        //获取上级部门id
        AdminUserDO user = adminUserService.getUser(loginUser.getId());
        DeptDO dept = deptService.getDept((user.getDeptId()));
        patientInfo.setDeptId(dept.getParentId());
        //设置已上报县级,上报状态：1-已上报县级，2-待上报，3-数据待完善，4-数据上报成功，
        patientInfo.setReportStatus(ReportConstant.COUNTY_REPORTED);
        patientInfoMapper.insert(patientInfo);
        return success(0,patientInfo.getId(),"创建上报精神病患者信息成功");
    }



    @Override
    @LogRecord(success = LogRecordConstants.REPORTER_CREATE_SUCCESS,
            operator = "{{#currentUser}}",
            type = LogRecordConstants.REPORTER,
            fail = "上报病人信息失败，失败原因：「{{#_errorMsg}}」",
            subType = LogRecordConstants.REPORTER_CREATE,bizNo = LogRecordConstants.REPORTER_CREATE_BIZ_NO)
    public CommonResult<Long> createPatientInfo(PatientInfoSaveReqVO createReqVO, LoginUser loginUser) {

        //获取该人员最新的上报信息
        PatientInfoDO lastPerson = getLastPerson(createReqVO);
        if (lastPerson != null){
            // 已上报县级状态，等待县级审核
            if (ReportConstant.COUNTY_REPORTED.equals(lastPerson.getReportStatus())
                    && lastPerson.getDiagnosisStatus() == null){
                return error(999,"该身份证患者已录入且处于已上报县级状态，等待县级审核，无需再次上报");
            }
            // 待上报
            if (ReportConstant.TO_BE_REPORTED.equals(lastPerson.getReportStatus())
                    && lastPerson.getDiagnosisStatus() == null){
                return error(999,"该身份证患者已录入且处于待上报状态，等待乡镇上报，无需再次录入，如需录入请将其删除");
            }
            // 已存在新筛查库中，且已确诊
            if ((ReportConstant.DATA_INCOMPLETE.equals(lastPerson.getReportStatus())
                    || ReportConstant.DATA_REPORT_SUCCESS.equals(lastPerson.getReportStatus()))
                    && ReportConstant.CONFIRMED.equals(lastPerson.getDiagnosisStatus())){
                return error(999,"该身份证已存在新筛查库中，且已确诊，无需再次上报");
            }
            // 已上报县级，且已排除
            if (ReportConstant.COUNTY_REPORTED.equals(lastPerson.getReportStatus())
                    && ReportConstant.EXCLUDED.equals(lastPerson.getDiagnosisStatus())){
                return  createPatient(createReqVO,loginUser);
            }
            else {
                System.out.println("未知情况上报"+lastPerson);
                return  createPatient(createReqVO,loginUser);
            }
        }
        //没有查到就上报此人
        else {
            return  createPatient(createReqVO,loginUser);
        }
    }

    @Override
    @LogRecord(success = LogRecordConstants.REPORTER_UPDATE_SUCCESS,
            operator = "{{#currentUser}}",
            type = LogRecordConstants.REPORTER,
            fail = "更新病人信息失败，失败原因：「{{#_errorMsg}}」",
            subType = LogRecordConstants.REPORTER_UPDATE,bizNo = "{{#updateReqVO.id}}")
    public CommonResult<Boolean> updatePatientInfo(PatientInfoSaveReqVO updateReqVO) {
        // 校验存在
        PatientInfoDO patientInfoDO = validatePatientInfoExists(updateReqVO.getId());
        updateReqVO.setIdNumber(patientInfoDO.getIdNumber());
        //操作日志上下文
        LogRecordContext.putVariable("patientName",updateReqVO.getPatientName());
        LogRecordContext.putVariable("idNumber",updateReqVO.getIdNumber());
        //上报状态：1-已上报县级，2-待上报，3-数据待完善，4-数据上报成功，
        // 只有上报状态是：待上报，诊断状态是null值才允许更新
        if (patientInfoDO != null && ReportConstant.TO_BE_REPORTED.equals(patientInfoDO.getReportStatus()) &&  patientInfoDO.getDiagnosisStatus()==null){
            PatientInfoDO updateObj = BeanUtils.toBean(updateReqVO, PatientInfoDO.class);
            patientInfoMapper.updateById(updateObj);
            //操作日志上下文
            LogRecordContext.putVariable("status","成功");
            LogRecordContext.putVariable("oldDiagnosisStatus",updateReqVO.getDiagnosisStatus());
            LogRecordContext.putVariable("newDiagnosisStatus",updateReqVO.getDiagnosisStatus());
            LogRecordContext.putVariable("oldReportStatus","待上报");
            LogRecordContext.putVariable("newReportStatus","已上报县级");
            return success(0,"更新上报精神病患者信息成功");
        }else {
            LogRecordContext.putVariable("status","失败");
            LogRecordContext.putVariable("oldDiagnosisStatus",updateReqVO.getDiagnosisStatus());
            LogRecordContext.putVariable("newDiagnosisStatus",updateReqVO.getDiagnosisStatus());
            LogRecordContext.putVariable("oldReportStatus","待上报");
            LogRecordContext.putVariable("newReportStatus","待上报");
            return error(999,"更新上报精神病患者信息失败：该身份证患者不是待上报状态，且已有诊断结果");
        }
    }

    @Override
    @LogRecord(success = LogRecordConstants.REPORTER_UPDATE_SUCCESS,
            operator = "{{#currentUser}}",
            type = LogRecordConstants.REPORTER,
            fail = "更新病人信息失败，失败原因：「{{#_errorMsg}}」",
            subType = LogRecordConstants.REPORTER_UPDATE,bizNo = "{{#updateReqVO.id}}")
    public CommonResult<Boolean> updatePatientInfoReport(PatientInfoSaveReqVO updateReqVO, LoginUser loginUser) {
        // 校验存在
        PatientInfoDO patientInfoDO = validatePatientInfoExists(updateReqVO.getId());
        updateReqVO.setIdNumber(patientInfoDO.getIdNumber());
        //操作日志上下文
        LogRecordContext.putVariable("patientName",updateReqVO.getPatientName());
        LogRecordContext.putVariable("idNumber",updateReqVO.getIdNumber());
        //上报状态：1-已上报县级，2-待上报，3-数据待完善，4-数据上报成功，
        // 只有上报状态是：待上报，诊断状态是null值才允许重新上报
        if (patientInfoDO != null && ReportConstant.TO_BE_REPORTED.equals(patientInfoDO.getReportStatus()) &&  patientInfoDO.getDiagnosisStatus()==null){
            //获取上级部门id
            DeptDO dept = deptService.getDept(updateReqVO.getOrginDeptId());
            updateReqVO.setDeptId(dept.getParentId());
            //设置已上报县级,上报状态：1-已上报县级，2-待上报，3-数据待完善，4-数据上报成功，
            updateReqVO.setReportStatus(ReportConstant.COUNTY_REPORTED);
            PatientInfoDO updateObj = BeanUtils.toBean(updateReqVO, PatientInfoDO.class);
            // 设置上报时间
            updateObj.setReportTime(LocalDateTime.now());
            patientInfoMapper.updateById(updateObj);
            //操作日志上下文
            LogRecordContext.putVariable("status","成功");
            LogRecordContext.putVariable("oldDiagnosisStatus",updateReqVO.getDiagnosisStatus());
            LogRecordContext.putVariable("newDiagnosisStatus",updateReqVO.getDiagnosisStatus());
            LogRecordContext.putVariable("oldReportStatus","待上报");
            LogRecordContext.putVariable("newReportStatus","已上报县级");
            return success(0,"上报精神病患者成功");
        }else {
            LogRecordContext.putVariable("status","失败");
            LogRecordContext.putVariable("oldDiagnosisStatus",updateReqVO.getDiagnosisStatus());
            LogRecordContext.putVariable("newDiagnosisStatus",updateReqVO.getDiagnosisStatus());
            LogRecordContext.putVariable("oldReportStatus","待上报");
            LogRecordContext.putVariable("newReportStatus","待上报");
            return error(999,"更新上报精神病患者状态失败：该身份证患者不是待上报状态，且已有诊断结果");
        }
    }

    @Override
    @LogRecord(success = LogRecordConstants.REPORTER_UPDATE_REPORT_SUCCESS,
            operator = "{{#currentUser}}",
            type = LogRecordConstants.REPORTER,
            fail = "更新病人信息失败，失败原因：「{{#_errorMsg}}」",
            subType = LogRecordConstants.REPORTER_UPDATE,bizNo = "{{#updateReqVO.id}}")
    public CommonResult<Boolean> updatePatientInfoReturn(PatientInfoSaveReqVO updateReqVO) {
        // 校验存在
        PatientInfoDO patientInfoDO = validatePatientInfoExists(updateReqVO.getId());
        updateReqVO.setIdNumber(patientInfoDO.getIdNumber());
        //操作日志上下文
        LogRecordContext.putVariable("patientName",updateReqVO.getPatientName());
        LogRecordContext.putVariable("idNumber",updateReqVO.getIdNumber());
        //有诊断状态不允许撤回
        if (patientInfoDO != null && patientInfoDO.getDiagnosisStatus() != null){
            LogRecordContext.putVariable("status","失败");
            return error(999,"撤回患者上报状态失败：该身份证患者已有诊断结果");
        }else {
            // 只有上报状态是：上报县级，无诊断状态才允许撤回
            if (patientInfoDO != null && ReportConstant.COUNTY_REPORTED.equals(patientInfoDO.getReportStatus())){
                //获取原来的部门id
                updateReqVO.setDeptId(updateReqVO.getOrginDeptId());
                //设置撤回,上报状态：1-已上报县级，2-待上报，3-数据待完善，4-数据上报成功，
                updateReqVO.setReportStatus(ReportConstant.TO_BE_REPORTED);
                //设置上报时间为null
                updateReqVO.setReportTime(null);
                PatientInfoDO updateObj = BeanUtils.toBean(updateReqVO, PatientInfoDO.class);
                patientInfoMapper.updateById(updateObj);
//            updatePatientInfo(updateReqVO);
                LogRecordContext.putVariable("status","成功");
                LogRecordContext.putVariable("oldReportStatus","已上报县级");
                LogRecordContext.putVariable("newReportStatus","待上报");
                return success(0,"撤回患者上报状态成功");
            }else {
                LogRecordContext.putVariable("status","失败");
                return error(999,"撤回患者上报状态失败：该身份证患者不是已上报县级状态");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = PATIENTS_PAGE, allEntries = true)
    @LogRecord(success = LogRecordConstants.REPORTER_UPDATE_DIAGNOSED_SUCCESS,
            operator = "{{#currentUser}}",
            type = LogRecordConstants.REPORTER,
            fail = "更新病人信息失败，失败原因：「{{#_errorMsg}}」",
            subType = LogRecordConstants.REPORTER_UPDATE,bizNo = "{{#updateReqVO.id}}")
    public void updatePatientInfoDiagnosis(PatientInfoSaveReqVO updateReqVO) {
        // 校验存在
        PatientInfoDO old = validatePatientInfoExists(updateReqVO.getId());
        //更新身份证
        if (old != null && !StringUtils.isBlank(old.getIdNumber())){
            updateReqVO.setIdNumber(old.getIdNumber());
        }
        // 更新
        PatientInfoDO updateObj = BeanUtils.toBean(updateReqVO, PatientInfoDO.class);
        //如果确诊新增基本信息管理
        if (old != null && ReportConstant.CONFIRMED.equals(updateReqVO.getDiagnosisStatus())){
            PatientsDOSaveReqVO insertObj = BeanUtils.toBean(updateReqVO, PatientsDOSaveReqVO.class);
            //赋值联系人姓名
            insertObj.setContactName(updateObj.getContactPerson());
            //插入基本信息数据库
            insertObj.setId(null);
            //插入末次随访时间和末次修改时间为当前时间
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            insertObj.setLastFollowupDate(sdf.format((new Date())));
            //必须加不然基本信息查询不到
            insertObj.setLastModified(sdf.format((new Date())));
            insertObj.setCurrentAddress(updateObj.getAddress());
            //重新赋值生日
            if (updateReqVO.getBirthDate()!=null){
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
                insertObj.setBirthDate(formatter.format((updateReqVO.getBirthDate())));
            }

            //赋值机构id
            insertObj.setDeptId(String.valueOf(updateReqVO.getOrginDeptId()));
            //新增病人赋值18位的0
            insertObj.setPatientCode(Config.HAS_DIAGNOSED_PATIENT_CODE);
            patientsDOService.createDO(insertObj);
            //设置数据带完善,上报状态：：1-已上报县级，2-待上报，3-数据待完善，4-数据上报成功，
            updateObj.setReportStatus(ReportConstant.DATA_INCOMPLETE);
            patientInfoMapper.updateById(updateObj);
        }
        //如果排除移到乡镇让乡镇人员看到
        else if (old != null && ReportConstant.EXCLUDED.equals(updateReqVO.getDiagnosisStatus())) {
            //排除情况设置上报状态为已上报县级
            updateObj.setReportStatus(ReportConstant.COUNTY_REPORTED);
            //获取原来用户的部门id
            patientInfoMapper.updateById(updateObj);
            //删除基本信息表的数据，条件为18位的0和身份证，防止出现真实数据误删除这种情况
            PatientsDODO delObj = BeanUtils.toBean(updateReqVO, PatientsDODO.class);
            delObj.setIdNumber(updateReqVO.getIdNumber());
            delObj.setPatientCode(Config.HAS_DIAGNOSED_PATIENT_CODE);
            patientsDOService.deleteDOByCounty(delObj);
        }
        //操作日志上下文
        LogRecordContext.putVariable("patientName",updateReqVO.getPatientName());
        LogRecordContext.putVariable("idNumber",updateReqVO.getIdNumber());
        LogRecordContext.putVariable("oldDiagnosisStatus",old.getDiagnosisStatus());
        LogRecordContext.putVariable("newDiagnosisStatus",updateReqVO.getDiagnosisStatus());
    }

    @Override
    @LogRecord(success = LogRecordConstants. REPORTER_DELETE_SUCCESS,
            operator = "{{#currentUser}}",
            type = LogRecordConstants.REPORTER,
            fail = "删除病人信息失败，失败原因：「{{#_errorMsg}}」",
            subType = LogRecordConstants.REPORTER_DELETE,bizNo = "{{#id}}")
    public void deletePatientInfo(Long id) {
        // 校验存在
        validatePatientInfoExists(id);
        // 删除
        patientInfoMapper.deleteById(id);
    }

    //根据id查患者是否存在
    private PatientInfoDO validatePatientInfoExists(Long id) {
        PatientInfoDO patientInfoDO = patientInfoMapper.selectById(id);
        if (patientInfoMapper.selectById(id) == null) {
            throw exception(PATIENT_INFO_NOT_EXISTS);
        }else {return patientInfoDO;}
    }

    //根据特定条件查患者是否存在
    private PatientInfoDO getLastPerson(PatientInfoSaveReqVO vo) {
        //查询最新的该身份证上报信息
        return patientInfoMapper.selectOne(new LambdaQueryWrapperX<PatientInfoDO>()
                .eq(PatientInfoDO::getIdNumber,vo.getIdNumber())
                .orderByDesc(PatientInfoDO::getCreateTime)
                .last("LIMIT 1")
        );
    }


    @Override
    @LogRecord(success = LogRecordConstants. REPORTER_DETAIL_SUCCESS,
            operator = "{{#currentUser}}",
            type = LogRecordConstants.REPORTER,
            fail = "查看病人信息失败，失败原因：「{{#_errorMsg}}」",
            subType = LogRecordConstants.REPORTER_DETAIL,bizNo = "{{#id}}")
    public PatientInfoDO getPatientInfo(Long id) {
        return patientInfoMapper.selectById(id);
    }

    @Override
    @LogRecord(success = LogRecordConstants. REPORTER_PAGE_SUCCESS,
            operator = "{{#currentUser}}",
            type = LogRecordConstants.REPORTER,
            fail = "查看病人信息分页失败，失败原因：「{{#_errorMsg}}」",
            subType = LogRecordConstants.REPORTER_PAGE,bizNo = LogRecordConstants.REPORTER_PAGE_BIZ_NO)
    public PageResult<PatientInfoDO> getPatientInfoPageByTown(PatientInfoPageReqVO pageReqVO) {
        //没有部门则默认查看本级及以下的数据
        if (pageReqVO.getOrginDeptId()==null || pageReqVO.getOrginDeptId().isEmpty()){
            List<Long> deptIds = bigScreenService.getDeptIds(null);
            pageReqVO.setOrginDeptId(deptIds);
        }
        return patientInfoMapper.selectPage(pageReqVO);
    }
    @Override
    @LogRecord(success = LogRecordConstants. REPORTER_PAGE_SUCCESS,
            operator = "{{#currentUser}}",
            type = LogRecordConstants.REPORTER,
            fail = "查看病人信息分页失败，失败原因：「{{#_errorMsg}}」",
            subType = LogRecordConstants.REPORTER_PAGE,bizNo = LogRecordConstants.REPORTER_PAGE_BIZ_NO)
    public PageResult<PatientInfoDO> getPatientInfoPageByCounty(PatientInfoPageReqVO pageReqVO) {
        //没有部门则默认查看本级及以下的数据
        if (pageReqVO.getOrginDeptId()==null || pageReqVO.getOrginDeptId().isEmpty()){
            List<Long> deptIds = bigScreenService.getDeptIds(null);
            pageReqVO.setOrginDeptId(deptIds);
        }
        //县区只看上报状态： 1-已上报县级，3-数据待完善，4-数据上报成功，（1-已上报县级，2-待上报，3-数据待完善，4-数据上报成功，）
        PageResult<PatientInfoDO> patientInfoDOPageResult = patientInfoMapper.selectPageByCountry(pageReqVO);
        return patientInfoDOPageResult;
    }


}